<?php

class slopeone
{
	
	private $network	= FALSE;
	private $id		= FALSE;
	private $user	= FALSE;
	private $api_id		= 0;
	private $to_user		= FALSE;
	private $group		= FALSE;
	private $message		= '';
	private $mentioned	= array();
	private $attached		= array();
	private $posttags		= 0;
	private $db1;
	private $db2;
	private $cache;

    function __construct()
    {
    	global $C;
		$this->cache	= & $GLOBALS['cache'];
		$this->db1		= & $GLOBALS['db1'];
		$this->db2		= FALSE;
		$this->api_id	= $C->API_ID;
		$n	= & $GLOBALS['network'];
		if( $n->id ) {
			$u	= & $GLOBALS['user'];
			if($u->is_logged && $u->info->network_id==$n->id) {
				$this->network	= $n;
				$this->user		= $u->info;
				$this->db2	= & $GLOBALS['db2'];
			}
		}
		$this->id	= FALSE;
    }
    

    /**
     * Init SlopeOneTable
     *
     * Use factory pattern
     * Specify the mode use 'PHP' or 'MySQL'
     * If you user 'PHP' mode, it's a pure php implementation, and it might be very slow
     * You can use 'MySQL' mode, it's based on mysql procedure, and it will be mutch faster.
     * @param string $factory
     */
    public function initSlopeOneTable($factory = 'PHP')
    {
       // set_time_limit(0);
        
        /**
         * If the mode is not PHP or MySQL, then it will be set as 'PHP'
         */
        ($factory != 'PHP' && $factory != 'MySQL') && ($factory = 'PHP');
        
        /**
         * Delete all the data of oso_slope_one
         */
        $db2->query('TRUNCATE TABLE `oso_slope_one`');
        
        /**
         * Form the function
         */
        $func = '_initSlopeOneTableBy' . $factory;
        
        /**
         * Execute the function
         */
        $this->$func();
    }
    
    /**
     * Init SlopeOneTable By PHP
     *
     * A pure php implementation, use it just for fun.
     */
    public function _initSlopeOneTableByPHP()
    {        
        /**
         * Get distinct item_id
         */
        $db2->query('SELECT DISTINCT item_id FROM oso_user_ratings');

    	while($o = $db2->fetch_object()) {
    		$slopeOneSql = 'insert into oso_slope_one (select a.item_id as item_id1,b.item_id as item_id2,count(*) as times, sum(a.rating-b.rating) as rating from oso_user_ratings a,oso_user_ratings b where a.item_id = '
                         .$o->item_id.' and b.item_id != a.item_id and a.user_id=b.user_id group by a.item_id,b.item_id)';
			$db2->query($slopeOneSql);
		}
				
    }
    
    /**
     * Init SlopeOneTable By MySQL
     *
     * A MySQL procedure implementation, use it in production environment
     * You can also call the procedure in shell
     */
    private function _initSlopeOneTableByMySQL()
    {
        if (!$this->_hasProcedure())
        {
            $this->_createProcedure();
        }
        $db2->query('call slope_one');
    }
    
    /**
     * Check if exists the procedurn
     *
     * @return boolean
     */
    private function _hasProcedure()
    {
    	$db2->query('show procedure status where Db = "slope_one" and name= "slope_one"');
    	$obj = $this->db2->fetch_object();
    	return !emtpy($obj) ? true : false;
    }
    
    /**
     * Create procedure
     *
     */
    private function _createProcedure()
    {
        $sql = '
            CREATE PROCEDURE `slope_one`()
                begin                    
                    DECLARE tmp_item_id int;
                    DECLARE done int default 0;                    
                    DECLARE mycursor CURSOR FOR select distinct item_id from oso_user_ratings;
                    DECLARE CONTINUE HANDLER FOR NOT FOUND set done=1;
                    open mycursor;
                    while (!done) do
                        fetch mycursor into tmp_item_id;
                        if (!done) then
                            insert into oso_slope_one (select a.item_id as item_id1,b.item_id as item_id2,count(*) as times, sum(a.rating-b.rating) as rating from oso_user_ratings a,oso_user_ratings b where a.item_id = tmp_item_id and b.item_id != a.item_id and a.user_id=b.user_id group by a.item_id,b.item_id);
                        end if;
                    END while;
                    close mycursor;
                end
        ';
        $db2->query($sql);
    }

    /**
     * Insert new data
     *
     */
    public function selectDataUserId($userId, $rating)
    {
        $sql = "select * from oso_user_ratings where user_id='".$userId."' and rating='".$rating."'";
        $db2->query($sql);
		while($o = $db2->fetch_object()) {
			$items[]=$o->item_id;
	    }
		return $items;
    }
 
    /**
     * Insert new data
     */
    public function insertNewData($userId, $itemId,$rating)
    {
        $sql = "insert into oso_user_ratings (user_id, item_id, rating) values ('".$userId."', '".$itemId."', '".$rating."')";
        $db2->query($sql);
		return true;
    }
   
    /**
     * Get recommended items by item's id 
     *
     */
    public function getRecommendedItemsById($itemId, $limit = 20)
    {
        $sql = 'select item_id2 from oso_slope_one where item_id1 = '
             . $itemId
             . ' group by item_id2 order by sum(rating/times) limit '
             . $limit;
             
        $db2->query($sql);

		$i=0;
		while ($o = $db2->fetch_object()) {
			$items[$i]=$o->item_id2;$i++;
        }
		return $items;
    }
    
    /**
     * Get recommended items by user's id
     *
     */
    public function getRecommendedItemsByUser($userId, $limit = 20)
    {

        $sql = 'select s.item_id2 from oso_slope_one s,oso_user_ratings u where u.user_id = '
             . $userId
             . ' and s.item_id1 = u.item_id and s.item_id2 != u.item_id group by s.item_id2 order by sum(u.rating * s.times - s.rating)/sum(s.times) desc limit '
             . $limit;
		$db2->query($sql);

		while ($o = $db2->fetch_object()) {
			$user[]=$o->item_id2;
        }

		return $user;
    }

}
?>
